/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
 
package com.cburch.logisim.UItools;

import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;

public class GraphicsUtil {
    public static final int H_LEFT = -1;
    public static final int H_CENTER = 0;
    public static final int H_RIGHT = 1;
    public static final int V_TOP = -1;
    public static final int V_CENTER = 0;
    public static final int V_BASELINE = 1;
    public static final int V_BOTTOM = 2;

    /**
	 * Set the stroke width of a Graphics object.
	 *
	 * @param	Graphics		graphics object to change the stroke width of
	 * @param	int		size of stroke width 
	 * @return	CanvasModel		model the action is associated with
	 */
    static public void switchToWidth(Graphics g, int width) {
        if(g instanceof Graphics2D) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setStroke(new BasicStroke((float) width));
        }
    }

	/**
	 * Draw an arc on a graphics object. All angles are in degrees
	 * and 0 degrees is the 3 o'clock position on a clock.
	 *
	 * @param	Graphics		graphics object to draw the arc on
	 * @param	int		x coordinate of the center of the arc
	 * @param	int		y coordinate of the center of the arc
	 * @param	int		radius of the arc
	 * @param	int		the angle to start the arc at
	 * @param	int		the length of the arc 
	 * @return	void	
	 */
    static public void drawCenteredArc(Graphics g, int x, int y,
            int r, int start, int dist) {
        g.drawArc(x - r, y - r, 2 * r, 2 * r, start, dist);
    }

	/**
	 * Gets a bounding box for text on a Graphics object with a given 
	 * font, string, position and alignments.
	 *
	 * @param	Graphics		graphics object the text would be on
	 * @param	Font		font type for the text in the bounds
	 * @param	String		text that would be in text bounds
	 * @param	int		x coordinate of the text bounds
	 * @param	int		y coordinate of the text bounds
	 * @param	int		type of horizontal alignment
	 * @param	int		type of vertical alignment
	 * @return	Rectangle		
	 */
    static public Rectangle getTextBounds(Graphics g, Font font,
            String text, int x, int y, int halign, int valign) {
        if(g == null) return new Rectangle(x, y, 0, 0);
        Font oldfont = g.getFont();
        if(font != null) g.setFont(font);
        Rectangle ret = getTextBounds(g, text, x, y, halign, valign);
        if(font != null) g.setFont(oldfont);
        return ret;
    }
    
	/**
	 * Gets a bounding box for text on a Graphics object with a given 
	 * string, position and alignments. Uses the graphics set font for
	 * the text bounds.
	 *
	 * @param	Graphics		graphics object the text would be on
	 * @param	String		text that would be in text bounds
	 * @param	int		x coordinate of the text bounds
	 * @param	int		y coordinate of the text bounds
	 * @param	int		type of horizontal alignment
	 * @param	int		type of vertical alignment
	 * @return	Rectangle		
	 */
    static public Rectangle getTextBounds(Graphics g, String text,
            int x, int y, int halign, int valign) {
        if(g == null) return new Rectangle(x, y, 0, 0);
        FontMetrics mets = g.getFontMetrics();
        int width = mets.stringWidth(text);
        int ascent = mets.getAscent();
        int height = ascent + mets.getDescent();
        Rectangle ret = new Rectangle(x, y, width, height);
        
        switch(halign) {
            case H_CENTER: ret.translate(-(width / 2), 0); break;
            case H_RIGHT:  ret.translate(-width, 0); break;
            default: ;
        }
        switch(valign) {
            case V_TOP:      break;
            case V_CENTER:   ret.translate(0, -(ascent / 2)); break;
            case V_BASELINE: ret.translate(0, -ascent); break;
            case V_BOTTOM:   ret.translate(0, -height); break;
            default: ;
        }
        return ret;
    }

	/**
	 * Draw text on a graphics object with a given font, string,
	 * position and alignments.
	 *
	 * @param	Graphics		graphics object to draw the text on
	 * @param	Font		set font type for the text
	 * @param	String		text to place in the text bounds
	 * @param	int		x coordinate of the text bounds
	 * @param	int		y coordinate of the text bounds
	 * @param	int		type of horizontal alignment
	 * @param	int		type of vertical alignment
	 * @return	void		
	 */
    static public void drawText(Graphics g, Font font,
            String text, int x, int y, int halign, int valign) {
        Font oldfont = g.getFont();
        if(font != null) g.setFont(font);
        drawText(g, text, x, y, halign, valign);
        if(font != null) g.setFont(oldfont);
    }
    
	/**
	 * Draw text on a graphics object with a given font, string,
	 * position and alignments. Uses the graphics set font for
	 * the text.
	 *
	 * @param	Graphics		graphics object to draw the text on
	 * @param	String		text to draw
	 * @param	int		x coordinate of the text
	 * @param	int		y coordinate of the text
	 * @param	int		type of horizontal alignment
	 * @param	int		type of vertical alignment
	 * @return	void		
	 */
    static public void drawText(Graphics g, String text,
            int x, int y, int halign, int valign) {
        if(text.length() == 0) return;
        Rectangle bd = getTextBounds(g, text, x, y, halign, valign);
        g.drawString(text, bd.x, bd.y + g.getFontMetrics().getAscent());
    }
    
	/**
	 * Draws horizontally and vertically centered text on a graphics object
	 * with the given text at the given position.
	 *
	 * @param	Graphics		graphics object to draw the text on
	 * @param	String		text to draw
	 * @param	int		x coordinate of the text
	 * @param	int		y coordinate of the text
	 * @return	void		
	 */
    static public void drawCenteredText(Graphics g, String text,
            int x, int y) {
        drawText(g, text, x, y, H_CENTER, V_CENTER);
    }

	/**
	 * Draws an arrow on a graphics object. The arrow head appears at
	 * the end position.
	 *
	 * @param	Graphics		graphics object to draw the arrow on
	 * @param	int		start x coordinate of the arrow
	 * @param	int		start y coordinate of the arrow
	 * @param	int		end x coordinate of the arrow
	 * @param	int		end y coordinate of the arrow
	 * @param	int		the length of the arrow head along the line
	 * @param	int		the "width" of the arrow in degrees
	 * @return	void		
	 */
    static public void drawArrow(Graphics g, int x0, int y0, int x1, int y1,
            int headLength, int headAngle) {
        double offs = headAngle * Math.PI / 180.0;
        double angle = Math.atan2(y0 - y1, x0 - x1);
        int[] xs = { x1 + (int) (headLength * Math.cos(angle + offs)), x1,
            x1 + (int) (headLength * Math.cos(angle - offs)) };
        int[] ys = { y1 + (int) (headLength * Math.sin(angle + offs)), y1,
            y1 + (int) (headLength * Math.sin(angle - offs)) };
        g.drawLine(x0, y0, x1, y1);
        g.drawPolyline(xs, ys, 3);
    }
    
    /**
	 * Rotate a list of points by an angle in degrees.
	 *
	 * @param	Graphics		graphics object to draw the arrow on
	 * @param	int		start x coordinate of the arrow
	 * @param	int	
	 */	
    static public void rotatePoints(Point[] pts, float degree)
    {
    	double x, y;
    	int tx, ty;
    	Point p;
    	double angle = degree * 0.0174532925;
    	
    	tx = pts[0].x;
    	ty = pts[0].y;
    	
    	for(int i = 1; i < pts.length; i++)
    	{
    		p = pts[i];    		
    		x = ((p.x - tx) * Math.cos(angle)) - ((p.y - ty) * Math.sin(angle)); 
    		y = ((p.x - tx) * Math.sin(angle)) + ((p.y - ty) * Math.cos(angle)); 
    		
    		p.x = (int)(x + tx);
    		p.y = (int)(y + ty);    		
    		
    	}
    }    
}


